<?php

namespace pmvc\io;

use pmvc\util\ClassUtil;

use pmvc\util\StringUtil;
use Exception;

/**
 * streamWrapper that supports classpath://
 */
class ClasspathStreamWrapper {

	const PROTOCOL = "classpath";

	public $context;
	private $uri;
	private $handle;

	/**
	 * Returns the target portion of the uri.
	 * @param string $uri
	 * @throws Exception
	 */
	private function getTarget($uri=null) {
		if (!isset($uri)) {
			$uri = $this->uri;
		}
		list($scheme, $target) = explode('://', $uri, 2);
		return rtrim($target, '\/');
	}

	/**
	 * Returns the real path of the uri.
	 * @param unknown_type $uri
	 * @return string
	 */
	private function getRealPath($uri=null) {
		if (!isset($uri)) {
			$uri = $this->uri;
		}
		return ClassUtil::getResourcePath($this->getTarget());
	}

	public function dir_closedir() {
		closedir($this->handle);
		return true;
	}

	public function dir_opendir($uri , $options) {
		$this->uri = $uri;
		$this->handle = opendir($this->getRealPath());
		return $this->handle;
	}

	public function dir_readdir () {
		return readdir($this->handle);
	}

	public function dir_rewinddir() {
		rewinddir($this->handle);
		return true;
	}

	public function mkdir($uri, $mode, $options) {
		$this->uri = $uri;
		$recursive = ($options & STREAM_MKDIR_RECURSIVE);
		return ($options & STREAM_REPORT_ERRORS)
			? mkdir($this->getTarget($uri), $mode, $recursive)
			: @mkdir($this->getTarget($uri), $mode, $recursive);
	}

	public function rename($from_uri, $to_uri) {
		return rename($this->getTarget($from_uri), $this->getTarget($to_uri));
	}

	public function rmdir($uri, $options) {
		$this->uri = $uri;
		return ($options & STREAM_REPORT_ERRORS)
			? rmdir($this->getTarget())
			: @rmdir($this->getTarget());
	}

	public function stream_cast($cast_as) {
		return $this->handle;
	}

	public function stream_close() {
		return fclose($this->handle);
	}

	public function stream_eof() {
		return feof($this->handle);
	}

	public function stream_flush() {
		return fflush($this->handle);
	}

	public function stream_lock($operation) {
		if (in_array($operation, array(LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB))) {
			return flock($this->handle, $operation);
		}
		return true;
	}

	
	public function stream_open($uri, $mode, $options, &$opened_path) {
		if (!StringUtil::startsWith($uri, self::PROTOCOL)) {
			throw new Exception("ClasspathStreamWrapper doesn't support: ".$uri);
		}
		$this->uri = $uri;
		$path = $this->getRealPath();
		$this->handle 	= ($options & STREAM_REPORT_ERRORS) ? fopen($path, $mode) : @fopen($path, $mode);
		if ($this->handle && $options & STREAM_USE_PATH) {
			$opened_url = $path;
		}
		return $this->handle;
	}

	public function stream_read($count) {
		return fread($this->handle, $count);
	}

	public function stream_seek($offset, $whence) {
		return !fseek($this->handle, $offset, $whence);
	}

	public function stream_stat() {
		return fstat($this->handle);
	}

	public function stream_tell() {
		return ftell($this->handle);
	}

	public function stream_truncate($new_size) {
		return ftruncate($this->handle, $new_size);
	}

	public function stream_write($data) {
		return fwrite($this->handle, $data);
	}

	public function unlink($uri) {
		$this->uri = $uri;
		return unlink($this->getRealPath());
	}

	public function url_stat($uri, $flags) {
		$this->uri = $uri;
		$path = $this->getRealPath();
		return ($flags & STREAM_URL_STAT_QUIET || !file_exists($path))
			? @stat($path) : stat($path);
	}

}


?>